﻿using System.IO;
using System.Net;
using System.Web;
using System.Xml;
using System.Text.RegularExpressions;
using System;

/// <summary>
/// A C# wrapper around the Google Closure Compiler web service.
/// </summary>
public class GoogleClosure
{
    private const string PostData = "js_code={0}&output_format=xml&output_info=compiled_code&compilation_level=SIMPLE_OPTIMIZATIONS";
    private const string ApiEndpoint = "http://closure-compiler.appspot.com/compile";

    /// <summary>
    /// Compresses the specified file using Google's Closure Compiler algorithm.
    /// <remarks>
    /// The file to compress must be smaller than 200 kilobytes.
    /// </remarks>
    /// </summary>
    /// <param name="file">The absolute file path to the javascript file to compress.</param>
    /// <returns>A compressed version of the specified JavaScript file.</returns>
    public string Compress(string file)
    {
        string source = File.ReadAllText(file);
        XmlDocument xml = CallApi(source);
        return xml.SelectSingleNode("//compiledCode").InnerText;
    }

    /// <summary>
    /// Calls the API with the source file as post data.
    /// </summary>
    /// <param name="source">The content of the source file.</param>
    /// <returns>The Xml response from the Google API.</returns>
    private static XmlDocument CallApi(string source)
    {
        using (WebClient client = new WebClient())
        {
            client.Headers.Add("content-type", "application/x-www-form-urlencoded");
            string data = string.Format(PostData, UrlHelper.Encode(source));
            string result = client.UploadString(ApiEndpoint, data);

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(result);
            return doc;
        }
    }
}

/// <summary>
/// URL encoding class.  Note: use at your own risk.
/// Written by: Ian Hopkins (http://www.lucidhelix.com)
/// Date: 2008-Dec-23
/// (Ported to C# by t3rse (http://www.t3rse.com))
/// </summary>
public class UrlHelper
{
    public static string Encode(string str)
    {
        var charClass = String.Format("0-9a-zA-Z{0}", Regex.Escape("-_.!~*'()"));
        return Regex.Replace(str,
            String.Format("[^{0}]", charClass),
            new MatchEvaluator(EncodeEvaluator));
    }

    public static string EncodeEvaluator(Match match)
    {
        return (match.Value == " ") ? "+" : String.Format("%{0:X2}", Convert.ToInt32(match.Value[0]));
    }

    public static string DecodeEvaluator(Match match)
    {
        return Convert.ToChar(int.Parse(match.Value.Substring(1), System.Globalization.NumberStyles.HexNumber)).ToString();
    }

    public static string Decode(string str)
    {
        return Regex.Replace(str.Replace('+', ' '), "%[0-9a-zA-Z][0-9a-zA-Z]", new MatchEvaluator(DecodeEvaluator));
    }
}